home *** CD-ROM | disk | FTP | other *** search
/ Freelog 115 / FreelogNo115-MaiJuin2013.iso / Internet / Filezilla Server / FileZilla_Server-0_9_41.exe / source / iputils.cpp < prev    next >
C/C++ Source or Header  |  2011-11-06  |  11KB  |  547 lines

  1. // FileZilla Server - a Windows ftp server
  2.  
  3. // Copyright (C) 2004 - Tim Kosse <tim.kosse@gmx.de>
  4.  
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9.  
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14.  
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. #include "stdafx.h"
  20. #include "iputils.h"
  21.  
  22. bool IsLocalhost(const CStdString& ip)
  23. {
  24.     if (ip.Left(4) == _T("127."))
  25.         return true;
  26.     if (GetIPV6ShortForm(ip) == _T("::1"))
  27.         return true;
  28.  
  29.     return false;
  30. }
  31.  
  32. bool IsValidAddressFilter(CStdString& filter)
  33. {
  34.     CStdString left;
  35.     int pos = filter.Find(_T("/"));
  36.     int prefixLength = 0;
  37.     if (!pos)
  38.         return false;
  39.     else if (pos != -1)
  40.     {
  41.         left = filter.Left(pos);
  42.         prefixLength = _ttoi(filter.Mid(pos + 1));
  43.         if (prefixLength <= 0 || prefixLength > 128)
  44.             return false;
  45.     }
  46.     else
  47.         left = filter;
  48.  
  49.     if (!IsIpAddress(left))
  50.         return false;
  51.  
  52.     if (left.Find(':') != -1)
  53.         left = GetIPV6ShortForm(left);
  54.     if (prefixLength)
  55.         filter.Format(_T("%s/%d"), (LPCTSTR)left, prefixLength);
  56.     else
  57.         filter = left;
  58.  
  59.  
  60.     return true;
  61. }
  62.  
  63. int DigitHexToDecNum(TCHAR c)
  64. {
  65.     if (c >= 'a')
  66.         return c - 'a' + 10;
  67.     if (c >= 'A')
  68.         return c - 'A' + 10;
  69.     else
  70.         return c - '0';
  71. }
  72.  
  73. static unsigned long const prefixMasksV4[] = {
  74.     0x00000000u,
  75.     0x80000000u,
  76.     0xc0000000u,
  77.     0xe0000000u,
  78.     0xf0000000u,
  79.     0xf8000000u,
  80.     0xfc000000u,
  81.     0xfe000000u,
  82.     0xff000000u,
  83.     0xff800000u,
  84.     0xffc00000u,
  85.     0xffe00000u,
  86.     0xfff00000u,
  87.     0xfff80000u,
  88.     0xfffc0000u,
  89.     0xfffe0000u,
  90.     0xffff0000u,
  91.     0xffff8000u,
  92.     0xffffc000u,
  93.     0xffffe000u,
  94.     0xfffff000u,
  95.     0xfffff800u,
  96.     0xfffffc00u,
  97.     0xfffffe00u,
  98.     0xffffff00u,
  99.     0xffffff80u,
  100.     0xffffffc0u,
  101.     0xffffffe0u,
  102.     0xfffffff0u,
  103.     0xfffffff8u,
  104.     0xfffffffcu,
  105.     0xfffffffeu,
  106.     0xffffffffu
  107. };
  108.  
  109. bool MatchesFilter(CStdString filter, CStdString ip)
  110. {
  111.     // A single asterix matches all IPs.
  112.     if (filter == _T("*"))
  113.         return true;
  114.  
  115.     // Check for IP range syntax.
  116.     int pos = filter.Find('/');
  117.     if (pos != -1)
  118.     {
  119.         // CIDR filter
  120.         int prefixLength = _ttoi(filter.Mid(pos+1));
  121.  
  122.         if (ip.Find(':') != -1)
  123.         {
  124.             // IPv6 address
  125.             CStdString left = GetIPV6LongForm(filter.Left(pos));
  126.             if (left.Find(':') == -1)
  127.                 return false;
  128.             ip = GetIPV6LongForm(ip);
  129.             LPCTSTR i = ip;
  130.             LPCTSTR f = left;
  131.             while (prefixLength >= 4)
  132.             {
  133.                 if (*i != *f)
  134.                     return false;
  135.  
  136.                 if (!*i)
  137.                     return true;
  138.  
  139.                 if (*i == ':')
  140.                 {
  141.                     ++i;
  142.                     ++f;
  143.                 }
  144.                 ++i;
  145.                 ++f;
  146.  
  147.                 prefixLength -= 4;
  148.             }
  149.             if (!prefixLength)
  150.                 return true;
  151.             
  152.             int mask;
  153.             if (prefixLength == 1)
  154.                 mask = 0x8;
  155.             else if (prefixLength == 2)
  156.                 mask = 0xc;
  157.             else
  158.                 mask = 0xe;
  159.  
  160.             return (DigitHexToDecNum(*i) & mask) == (DigitHexToDecNum(*f) & mask);
  161.         }
  162.         else
  163.         {
  164.             if (prefixLength < 0)
  165.                 prefixLength = 0;
  166.             else if (prefixLength > 32)
  167.                 prefixLength = 32;
  168.  
  169.             // IPv4 address
  170.             CStdString left = filter.Left(pos);
  171.             if (left.Find(':') != -1)
  172.                 return false;
  173.  
  174.             unsigned long i = ntohl(inet_addr(ConvToLocal(ip)));
  175.             unsigned long f = ntohl(inet_addr(ConvToLocal(left)));
  176.  
  177.             i &= prefixMasksV4[prefixLength];
  178.             f &= prefixMasksV4[prefixLength];
  179.             return i == f;
  180.         }
  181.     }
  182.     else
  183.     {
  184.         // Literal filter
  185.         if (filter.Find(':') != -1)
  186.             return filter == GetIPV6ShortForm(ip);
  187.         else
  188.             return filter == ip;
  189.     }
  190. }
  191.  
  192. bool ParseIPFilter(CStdString in, std::list<CStdString>* output /*=0*/)
  193. {
  194.     bool valid = true;
  195.  
  196.     in.Replace(_T("\n"), _T(" "));
  197.     in.Replace(_T("\r"), _T(" "));
  198.     in.Replace(_T("\t"), _T(" "));
  199.     while (in.Replace(_T("  "), _T(" ")));
  200.     in.TrimLeft(_T(" "));
  201.     in.TrimRight(_T(" "));
  202.     in += _T(" ");
  203.  
  204.     int pos;
  205.     while ((pos = in.Find(_T(" "))) != -1)
  206.     {
  207.         CStdString ip = in.Left(pos);
  208.         if (ip == _T(""))
  209.             break;
  210.         in = in.Mid(pos + 1);
  211.  
  212.         if (ip == _T("*") || IsValidAddressFilter(ip))
  213.         {
  214.             if (output)
  215.                 output->push_back(ip);
  216.         }
  217.         else
  218.             valid = false;
  219.     }
  220.  
  221.     return valid;
  222. }
  223.  
  224. CStdString GetIPV6LongForm(CStdString short_address)
  225. {
  226.     if (short_address[0] == '[')
  227.     {
  228.         if (short_address[short_address.GetLength() - 1] != ']')
  229.             return _T("");
  230.         short_address = short_address.Mid(1, short_address.GetLength() - 2);
  231.     }
  232.     short_address.MakeLower();
  233.  
  234.     TCHAR buffer[40] = { '0', '0', '0', '0', ':',
  235.                          '0', '0', '0', '0', ':',
  236.                          '0', '0', '0', '0', ':',
  237.                          '0', '0', '0', '0', ':',
  238.                          '0', '0', '0', '0', ':',
  239.                          '0', '0', '0', '0', ':',
  240.                          '0', '0', '0', '0', ':',
  241.                          '0', '0', '0', '0', 0
  242.                        };
  243.     TCHAR* out = buffer;
  244.  
  245.     const unsigned int len = short_address.GetLength();
  246.     if (len > 39)
  247.         return _T("");
  248.  
  249.     // First part, before possible ::
  250.     unsigned int i = 0;
  251.     unsigned int grouplength = 0;
  252.     for (i = 0; i < len + 1; i++)
  253.     {
  254.         const TCHAR& c = short_address[i];
  255.         if (c == ':' || !c)
  256.         {
  257.             if (!grouplength)
  258.             {
  259.                 // Empty group length, not valid
  260.                 if (!c || short_address[i + 1] != ':')
  261.                     return _T("");
  262.                 i++;
  263.                 break;
  264.             }
  265.  
  266.             out += 4 - grouplength;
  267.             for (unsigned int j = grouplength; j > 0; j--)
  268.                 *out++ = short_address[i - j];
  269.             // End of string...
  270.             if (!c)
  271.             {
  272.                 if (!*out)
  273.                     // ...on time
  274.                     return buffer;
  275.                 else
  276.                     // ...premature
  277.                     return _T("");
  278.             }
  279.             else if (!*out)
  280.             {
  281.                 // Too long
  282.                 return _T("");
  283.             }
  284.  
  285.             out++;
  286.  
  287.             grouplength = 0;
  288.             if (short_address[i + 1] == ':')
  289.             {
  290.                 i++;
  291.                 break;
  292.             }
  293.             continue;
  294.         }
  295.         else if ((c < '0' || c > '9') &&
  296.                  (c < 'a' || c > 'f'))
  297.         {
  298.             // Invalid character
  299.             return _T("");
  300.         }
  301.         // Too long group
  302.         if (++grouplength > 4)
  303.             return _T("");
  304.     }
  305.  
  306.     // Second half after ::
  307.  
  308.     TCHAR* end_first = out;
  309.     out = &buffer[38];
  310.     unsigned int stop = i;
  311.     for (i = len - 1; i > stop; i--)
  312.     {
  313.         if (out < end_first)
  314.         {
  315.             // Too long
  316.             return _T("");
  317.         }
  318.  
  319.         const TCHAR& c = short_address[i];
  320.         if (c == ':')
  321.         {
  322.             if (!grouplength)
  323.             {
  324.                 // Empty group length, not valid
  325.                 return _T("");
  326.             }
  327.  
  328.             out -= 5 - grouplength;
  329.  
  330.             grouplength = 0;
  331.             continue;
  332.         }
  333.         else if ((c < '0' || c > '9') &&
  334.                  (c < 'a' || c > 'f'))
  335.         {
  336.             // Invalid character
  337.             return _T("");
  338.         }
  339.         // Too long group
  340.         if (++grouplength > 4)
  341.             return _T("");
  342.         *out-- = c;
  343.     }
  344.     if (!grouplength && stop + 1 < len)
  345.     {
  346.         // Empty group length, not valid
  347.         return _T("");
  348.     }
  349.     out -= 5 - grouplength;
  350.     out += 2;
  351.  
  352.     int diff = out - end_first;
  353.     if (diff < 0 || diff % 5)
  354.         return _T("");
  355.  
  356.     return buffer;
  357. }
  358.  
  359. bool IsRoutableAddress(const CStdString& address)
  360. {
  361.     if (address.Find(_T(":")) != -1)
  362.     {
  363.         CStdString long_address = GetIPV6LongForm(address);
  364.         if (long_address.IsEmpty())
  365.             return false;
  366.         if (long_address[0] == '0')
  367.         {
  368.             // ::/128
  369.             if (long_address == _T("0000:0000:0000:0000:0000:0000:0000:0000"))
  370.                 return false;
  371.             // ::1/128
  372.             if (long_address == _T("0000:0000:0000:0000:0000:0000:0000:0001"))
  373.                 return false;
  374.  
  375.             if (long_address.Left(30) == _T("0000:0000:0000:0000:0000:ffff:"))
  376.             {
  377.                 // IPv4 mapped
  378.                 CStdString ipv4;
  379.                 ipv4.Format(_T("%d.%d.%d.%d"),
  380.                         DigitHexToDecNum(long_address[30]) * 16 + DigitHexToDecNum(long_address[31]),
  381.                         DigitHexToDecNum(long_address[32]) * 16 + DigitHexToDecNum(long_address[33]),
  382.                         DigitHexToDecNum(long_address[35]) * 16 + DigitHexToDecNum(long_address[36]),
  383.                         DigitHexToDecNum(long_address[37]) * 16 + DigitHexToDecNum(long_address[38]));
  384.                 return IsRoutableAddress(ipv4);
  385.             }
  386.  
  387.             return true;
  388.         }
  389.         if (long_address[0] == 'f')
  390.         {
  391.             if (long_address[1] == 'e')
  392.             {
  393.                 // fe80::/10 (link local)
  394.                 const TCHAR& c = long_address[2];
  395.                 int v;
  396.                 if (c >= 'a')
  397.                     v = c - 'a' + 10;
  398.                 else
  399.                     v = c - '0';
  400.                 if ((v & 0xc) == 0x8)
  401.                     return false;
  402.  
  403.                 return true;
  404.             }
  405.             else if (long_address[1] == 'c' || long_address[1] == 'd')
  406.             {
  407.                 // fc00::/7 (site local)
  408.                 return false;
  409.             }
  410.         }
  411.  
  412.         return true;
  413.     }
  414.     else
  415.     {
  416.         // Assumes address is already a valid IP address
  417.         if (address.Left(3) == _T("127") ||
  418.             address.Left(3) == _T("10.") ||
  419.             address.Left(7) == _T("192.168") ||
  420.             address.Left(7) == _T("169.254"))
  421.             return false;
  422.  
  423.         if (address.Left(3) == _T("172"))
  424.         {
  425.             CStdString middle = address.Mid(4);
  426.             int pos = address.Find(_T("."));
  427.             if (pos == -1)
  428.                 return false;
  429.             int part = _ttoi(middle.Left(pos));
  430.  
  431.             if (part >= 16 && part <= 31)
  432.                 return false;
  433.         }
  434.  
  435.         return true;
  436.     }
  437. }
  438.  
  439. bool IsIpAddress(const CStdString& address)
  440. {
  441.     if (GetIPV6LongForm(address) != _T(""))
  442.         return true;
  443.  
  444.     int segment = 0;
  445.     int dotcount = 0;
  446.     for (int i = 0; i < address.GetLength(); ++i)
  447.     {
  448.         const TCHAR& c = address[i];
  449.         if (c == '.')
  450.         {
  451.             if (address[i + 1] == '.')
  452.                 // Disallow multiple dots in a row
  453.                 return false;
  454.  
  455.             if (segment > 255)
  456.                 return false;
  457.             if (!dotcount && !segment)
  458.                 return false;
  459.             dotcount++;
  460.             segment = 0;
  461.         }
  462.         else if (c < '0' || c > '9')
  463.             return false;
  464.  
  465.         segment = segment * 10 + c - '0';
  466.     }
  467.     if (dotcount != 3)
  468.         return false;
  469.  
  470.     if (segment > 255)
  471.         return false;
  472.  
  473.     return true;
  474. }
  475.  
  476. CStdString GetIPV6ShortForm(const CStdString& ip)
  477. {
  478.     // This could be optimized a lot.
  479.  
  480.     // First get the long form in a well-known format
  481.     CStdString l = GetIPV6LongForm(ip);
  482.     if (l.IsEmpty())
  483.         return CStdString();
  484.  
  485.     LPCTSTR p = l;
  486.  
  487.     TCHAR outbuf[42];
  488.     *outbuf = ':';
  489.     TCHAR* out = outbuf + 1;
  490.  
  491.     bool segmentStart = true;
  492.     bool readLeadingZero = false;
  493.     while (*p)
  494.     {
  495.         switch (*p)
  496.         {
  497.         case ':':
  498.             if (readLeadingZero)
  499.                 *(out++) = '0';
  500.             *out++ = ':';
  501.             readLeadingZero = false;
  502.             segmentStart = true;
  503.             break;
  504.         case '0':
  505.             if (segmentStart)
  506.                 readLeadingZero = true;
  507.             else
  508.             {
  509.                 *out++ = '0';
  510.                 readLeadingZero = false;
  511.             }
  512.             break;
  513.         default:
  514.             readLeadingZero = false;
  515.             segmentStart = false;
  516.             *out++ = *p;
  517.             break;
  518.         }
  519.  
  520.         ++p;
  521.     }
  522.     *(out++) = ':';
  523.     *out = 0;
  524.  
  525.     // Replace longest run of consecutive zeroes
  526.     CStdString shortIp(outbuf);
  527.  
  528.     CStdString s = _T(":0:0:0:0:0:0:0:0:");
  529.     while (s.GetLength() > 2)
  530.     {
  531.         int pos = shortIp.Find(s);
  532.         if (pos != -1)
  533.         {
  534.             shortIp = shortIp.Left( pos + 1 ) + shortIp.Mid(pos + s.GetLength() -1);
  535.             break;
  536.         }
  537.  
  538.         s = s.Mid(2);
  539.     }
  540.     shortIp.Replace(_T(":::"), _T("::"));
  541.     if (shortIp[0] == ':' && shortIp[1] != ':')
  542.         shortIp = shortIp.Mid(1);
  543.     if (shortIp.GetLength() >= 2 && shortIp[shortIp.GetLength()-1] == ':' && shortIp[shortIp.GetLength()-2] != ':')
  544.         shortIp = shortIp.Left(shortIp.GetLength()-1);
  545.  
  546.     return shortIp;
  547. }